home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / System / Sample 2.4 Think C distribution / vol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-11  |  21.2 KB  |  725 lines  |  [TEXT/KAHL]

  1. /*______________________________________________________________________
  2.  
  3.     vol.c - Volume Selection Module.
  4.     
  5.     Copyright © 1988, 1989, 1990 Northwestern University.  Permission is granted
  6.     to use this code in your own projects, provided you give credit to both
  7.     John Norstad and Northwestern University in your about box or document.
  8.     
  9.     This reusable module implements volume selection as in Apple's 
  10.     standard file package.
  11.     
  12.     The caller supplies a Drive button, an Eject button, and a rectangle
  13.     in which the name of the currently selected volume should be displayed.
  14.     
  15.     The module takes care of cycling through selected on-line volumes,
  16.     processing hits in the drive and eject buttons, properly hiliting
  17.     these buttons, processing disk insertion events, and drawing the 
  18.     volume name in response to update events.
  19.     
  20.     In addition to the volume name displayed in a rectangle, the caller 
  21.     can also request that small floppy and hard drive icons be displayed.  
  22.     The module displays the appropriate small icon in a caller-specified 
  23.     rectangle.  The caller supplies the small icons.
  24.     
  25.     If the current system supports popup menus, the volume name rectangle is
  26.     framed with a drop shadow.  If the user clicks in this rectangle a popup
  27.     menu is presented listing all mounted volumes.
  28.     
  29.     All of the routines do error checking, and return an error code
  30.     as their function result.
  31.     
  32.     This module should only be used in a modal environment (e.g., modal
  33.     dialogs).  The reason is that it assumes only it is mounting and
  34.     unmounting volumes.  In a non-modal environment this assumption
  35.     is invalid.
  36.     
  37.     All of the code placed in its own segment named "vol", except for the
  38.     vol_Init routine, which is placed in segment voli.
  39. _____________________________________________________________________*/
  40.  
  41.  
  42. #include "vol.h"
  43. #include "utl.h"
  44.  
  45. #define nil 0
  46.  
  47. /*______________________________________________________________________
  48.  
  49.     Global Variables.
  50. _____________________________________________________________________*/
  51.  
  52.  
  53. static ControlHandle    DriveH;        /* handle to drive push button */
  54. static ControlHandle    EjectH;        /* handle to eject push button */
  55. static Rect                *NameRect;    /* pointer to volume name rectangle */
  56. static Rect                AdjNameRect;    /* rectangle enclosing current vol name,
  57.                                                 adjusted for width of name */
  58. static Rect                *IconRect;    /* pointer to small vol icon rectangle */
  59. static Handle            FloppyH;        /*    handle to small floppy icon */
  60. static Handle            HardH;        /* handle to small hard drive icon */
  61. static Boolean            UnmountFlag;    /* true to unmount ejected volumes */
  62. static short            CurVol;        /* index of currently selected volume,
  63.                                                 or 0 if none */
  64. static short            ApplVol;        /* vol ref num of vol contng current appl */
  65. static short            SysVol;        /* vol ref num of system vol */
  66. static Boolean            HavePopUp;     /* true if system supports popup menus */
  67.  
  68. /*______________________________________________________________________
  69.  
  70.     NextVol - Advance to the Next Volume.
  71.     
  72.     Exit:        function result = error code.
  73. _____________________________________________________________________*/
  74.  
  75.  
  76. static OSErr NextVol(void)
  77.  
  78. {
  79.     HParamBlockRec    pBlock;                /* vol info param block */
  80.     OSErr                rCode;                /* result code */
  81.     short                volInx;                /* volume index */
  82.     
  83.     pBlock.volumeParam.ioNamePtr = nil;
  84.     volInx = CurVol;
  85.     while (true) {
  86.         pBlock.volumeParam.ioVolIndex = ++volInx;
  87.         pBlock.volumeParam.ioVRefNum = 0;
  88.         if (rCode = PBHGetVInfo(&pBlock, false)) {
  89.             volInx = 0;
  90.         } else if (pBlock.volumeParam.ioVDrvInfo) {
  91.             CurVol = volInx;
  92.             return noErr;
  93.         };
  94.         if (volInx == CurVol) {
  95.             CurVol = 0;
  96.             return noErr;
  97.         };
  98.     };
  99. }
  100.  
  101. /*______________________________________________________________________
  102.  
  103.     HiliteDrive() - Hilite the Drive Button.
  104.     
  105.     The drive button is hilited iff there are at least two on-line
  106.     volumes.
  107. _____________________________________________________________________*/
  108.  
  109.  
  110. static void HiliteDrive(void)
  111.  
  112. {
  113.     HParamBlockRec    pBlock;                /* vol info param block */
  114.     short                volInx;                /* vol index */
  115.     short                numOnLine;            /* number of online vols */
  116.     OSErr                rCode;                /* result code */
  117.     
  118.     pBlock.volumeParam.ioNamePtr = nil;
  119.     volInx = 0;
  120.     numOnLine = 0;
  121.     while (true) {
  122.         pBlock.volumeParam.ioVolIndex = ++volInx;
  123.         pBlock.volumeParam.ioVRefNum = 0;
  124.         if (rCode = PBHGetVInfo(&pBlock, false)) break;
  125.         if (pBlock.volumeParam.ioVDrvInfo) numOnLine++;
  126.         if (numOnLine > 1 ) {
  127.             HiliteControl(DriveH, 0);
  128.             return;
  129.         };
  130.     };
  131.     HiliteControl(DriveH, 255);
  132. }
  133.  
  134. /*______________________________________________________________________
  135.  
  136.     HiliteEject() - Hilite the eject Button.
  137.     
  138.     Exit:        function result = error code.
  139.     
  140.     The eject button is hilited iff the current volume is ejectable.
  141. _____________________________________________________________________*/
  142.  
  143.  
  144. static OSErr HiliteEject(void)
  145.  
  146. {
  147.     short                vRefNum;                /* vol ref num of cur vol */
  148.     OSErr                rCode;                /* result code */
  149.     
  150.     /* If there is no current volume unhilite the eject button. */
  151.     
  152.     if (!CurVol) {
  153.         HiliteControl(EjectH, 255);
  154.         return noErr;
  155.     };
  156.     
  157.     /* Hilite the button iff the cur vol is ejectable. */
  158.     
  159.     if (rCode = vol_GetSel(&vRefNum)) return rCode;
  160.     HiliteControl(EjectH, utl_Ejectable(vRefNum) ? 0 : 255);
  161.     return noErr;
  162. }
  163.  
  164. /*______________________________________________________________________
  165.  
  166.     Inval - Invalidate the volume name and icon rectangles.
  167. _____________________________________________________________________*/
  168.  
  169.  
  170. static void Inval(void)
  171.  
  172. {
  173.     Rect        boxRect;
  174.  
  175.     boxRect = *NameRect;
  176.     InsetRect(&boxRect, -2, -2);
  177.     InvalRect(&boxRect);
  178.     if (IconRect) InvalRect(IconRect);
  179. }
  180.  
  181. /*______________________________________________________________________
  182.  
  183.     vol_Init - Initialize.
  184.     
  185.     Entry:    driveH = handle to drive push button control.
  186.                 ejectH = handle to eject push button control.
  187.                 nameRect = pointer to volume name rectangle.
  188.                 iconRect = pointer to small volume icon rectangle, 
  189.                     or nil if none.
  190.                 floppyH = handle to small floppy icon, or nil if none.
  191.                 hardH = handle to small hard drive icon, or nil if none.
  192.                 applSel = true if the initial volume should be the volume
  193.                     containing the current application.  False if the initial
  194.                     volume should be some other volume (if there is one).
  195.                 unmmountFlag = true if ejected floppies should also be 
  196.                     unmounted.  The boot volume and the volume containing the 
  197.                     current application are never unmounted.
  198.                     
  199.     Exit:        function result = error code.
  200.                     
  201.     vol_Init must be called before calling any of the other routines
  202.     in the module.  It may be called more than once to reinitialize
  203.     the module.
  204.                     
  205.     vol_Init saves the parameters in private globals, selects an 
  206.     appropriate initial volume, and hilites the drive and eject buttons 
  207.     appropriately.
  208.     
  209.     Don't forget to do a SetPort to the window before calling this routine.
  210. _____________________________________________________________________*/
  211.  
  212.  
  213. OSErr vol_Init (ControlHandle driveH, ControlHandle ejectH, 
  214.     Rect *nameRect, Rect *icnRect, Handle floppyH, 
  215.     Handle hardH, Boolean applSel, Boolean unmountFlag)
  216.     
  217. {
  218.  
  219.     HParamBlockRec    pBlock;                /* Vol info param block */
  220.     short                applInx;                /* index of application volume */
  221.     OSErr                rCode;                /* result code */
  222.     
  223.     /* Save parameter values in private global variables. */
  224.     
  225.     DriveH = driveH;
  226.     EjectH = ejectH;
  227.     NameRect = nameRect;
  228.     IconRect = icnRect;
  229.     FloppyH = floppyH;
  230.     HardH = hardH;
  231.     UnmountFlag = unmountFlag;
  232.     
  233.     /* Get applInx = index of volume containing current application,
  234.         and ApplVol = vol ref num of applicaton volume. */
  235.     
  236.     pBlock.volumeParam.ioNamePtr = nil;
  237.     ApplVol = utl_GetApplVol();
  238.     applInx = 0;
  239.     do {
  240.         pBlock.volumeParam.ioVolIndex = ++applInx;
  241.         pBlock.volumeParam.ioVRefNum = 0;
  242.         rCode = PBHGetVInfo(&pBlock, false);
  243.     } while (!rCode && pBlock.volumeParam.ioVRefNum != ApplVol);
  244.     if (rCode) return rCode;
  245.     
  246.     /* Select initial volume.  */
  247.     
  248.     if (applSel) {
  249.         CurVol = applInx;
  250.     } else {
  251.         CurVol = 0;
  252.         do {
  253.             pBlock.volumeParam.ioVolIndex = ++CurVol;
  254.             pBlock.volumeParam.ioVRefNum = 0;
  255.             rCode = PBHGetVInfo(&pBlock, false);
  256.         } while (!rCode && (!pBlock.volumeParam.ioVDrvInfo || 
  257.             pBlock.volumeParam.ioVRefNum == ApplVol));
  258.         if (rCode) CurVol = applInx;
  259.     };
  260.     
  261.     /* Get SysVol = vol ref num of system volume. */
  262.     
  263.     SysVol = utl_GetSysVol();
  264.     
  265.     /* Find out whether the system supports popup menus. */
  266.     
  267.     HavePopUp = utl_SysHasPopUp();
  268.         
  269.     /* Hilite buttons and invalidate rectangles. */
  270.     
  271.     HiliteDrive();
  272.     if (rCode = HiliteEject()) return rCode;
  273.     Inval();
  274.     return noErr;
  275. }
  276.  
  277. /*______________________________________________________________________
  278.  
  279.     vol_DoDrive - Process Drive Button Hit.
  280.                     
  281.     Exit:        function result = error code.
  282.     
  283.     This routine must be called whenever there's a hit in the Drive
  284.     button.  It advances to the next on-line volume, hilites the 
  285.     eject button appropriately, and invalidates the volume name and 
  286.     icon rectangles.
  287.     
  288.     To perfectly mimic the standard file package, you can also call this
  289.     routine whenever the tab key is pressed.
  290.     
  291.     Don't forget to do a SetPort to the window before calling this routine.
  292. _____________________________________________________________________*/
  293.  
  294.  
  295. OSErr vol_DoDrive (void)
  296.  
  297. {
  298.     OSErr        rCode;            /* result code */
  299.  
  300.     if (rCode = NextVol()) return rCode;
  301.     if (rCode = HiliteEject()) return rCode;
  302.     Inval();
  303.     return noErr;
  304. }
  305.  
  306. /*______________________________________________________________________
  307.  
  308.     vol_DoPopUp - Present Volume Popup Menu.
  309.     
  310.     Entry:    where = location of mouse down, local coords.
  311.                 menuID = menu id to use for popup menu.
  312.                     
  313.     Exit:        function result = error code.
  314.     
  315.     This routine should be called whenever there's a mouse hit in the volume 
  316.     name rectangle.  It builds and presents a pop up menu listing all the 
  317.     mounted volumes.  The current volume is set to the volume selected from 
  318.     the menu by the user.
  319.     
  320.     The routine returns immediately if the mouse down event is not inside
  321.     the volume name rectangle.  It also returns immediately if the ROM or
  322.     system does not support popup menus.
  323.     
  324.     Don't forget to do a SetPort to the window before calling this routine.
  325. _____________________________________________________________________*/
  326.  
  327.  
  328. OSErr vol_DoPopUp (Point where, short menuID)
  329.  
  330. {
  331.     MenuHandle        theMenu;                /* handle to popup menu */
  332.     long                theItem;                /* 16/menu number, 16/item number */
  333.     short                volInx;                /* index in volume list */
  334.     HParamBlockRec    pBlock;                /* vol info param block */
  335.     Str255            volName;                /* vol name */
  336.     OSErr                rCode;                /* result code */
  337.     Point                whereMenu;            /* loc of popup menu, global coords */
  338.     short                item;                    /* menu item number */
  339.     short                checkedItem;        /* menu item number of checked item */
  340.     unsigned char    *p;                    /* pointer into vol name string */
  341.     Rect                invertRect;            /* rectangle to be inverted */
  342.     Rect                popTestRect;        /* rectangle to hit test */
  343.     
  344.     /* Return if pop up menus are not available on this sytem. */
  345.     
  346.     if (!HavePopUp) return noErr;
  347.     
  348.     /* Return if mousedown not in volume name rectangle. */
  349.     
  350.     popTestRect = *NameRect;
  351.     popTestRect.right = AdjNameRect.right - 1;
  352.     if (!PtInRect(where, &popTestRect)) return noErr;
  353.     
  354.     /* Return if there is no current volume. */
  355.     
  356.     if (!CurVol) return noErr;
  357.     
  358.     /* Create the menu. */
  359.     
  360.     theMenu = NewMenu(menuID, (StringPtr)"\p");
  361.     
  362.     /* Fill the menu with the names of all currently mounted volumes.  Put
  363.         a check mark next to the currently selected volume. */
  364.     
  365.     volInx = item = 0;
  366.     pBlock.volumeParam.ioNamePtr = volName;
  367.     while (true) {
  368.         pBlock.volumeParam.ioVolIndex = ++volInx;
  369.         pBlock.volumeParam.ioVRefNum = 0;
  370.         rCode = PBHGetVInfo(&pBlock, false);
  371.         if (rCode) break;
  372.         if (pBlock.volumeParam.ioVDrvInfo) {
  373.             AppendMenu(theMenu, (StringPtr)"\p ");
  374.             if (*(volName+1) == '-') {
  375.                 /* vol name starts with '-': prepend a blank to the beginning
  376.                     of the name to avoid having the menu manager display it as
  377.                     a separator line. */
  378.                 for (p = volName + volName[0]; p > volName; p--) *(p+1) = *p;
  379.                 volName[1] = ' ';
  380.                 volName[0]++;
  381.             };
  382.             SetItem(theMenu, ++item, volName);
  383.             if (volInx == CurVol) 
  384.                 CheckItem(theMenu, checkedItem = item, true);
  385.         };
  386.     };
  387.         
  388.     /* Insert menu into menu bar. */
  389.     
  390.     InsertMenu(theMenu, -1);
  391.     
  392.     /* Pop it up.  Extract the item number selected.  Make the selected item
  393.         the current volume. */
  394.     
  395.     SetPt(&whereMenu, NameRect->left, NameRect->top);
  396.     LocalToGlobal(&whereMenu);
  397.     if (IconRect) {
  398.         invertRect = *IconRect;
  399.         invertRect.left--;
  400.         invertRect.right = NameRect->left;
  401.         InvertRect(&invertRect);
  402.     };
  403.     theItem = PopUpMenuSelect(theMenu, whereMenu.v, whereMenu.h, 
  404.         checkedItem);
  405.     if (IconRect) InvertRect(&invertRect);
  406.     if ((theItem >> 16) & 0xffff) {
  407.         item = theItem & 0xffff;
  408.         volInx = 0;
  409.         pBlock.volumeParam.ioNamePtr = nil;
  410.         while (true) {
  411.             pBlock.volumeParam.ioVolIndex = ++volInx;
  412.             pBlock.volumeParam.ioVRefNum = 0;
  413.             rCode = PBHGetVInfo(&pBlock, false);
  414.             if (rCode) break;
  415.             if (pBlock.volumeParam.ioVDrvInfo) {
  416.                 if (!(--item)) {
  417.                     CurVol = volInx;
  418.                     break;
  419.                 };
  420.             };
  421.         };
  422.         if (rCode = HiliteEject()) return rCode;
  423.         Inval();
  424.     };
  425.     
  426.     /* Delete and dispose of the menu and return. */
  427.     
  428.     DeleteMenu(menuID);
  429.     DisposeMenu(theMenu);
  430.     return noErr;
  431. }
  432.  
  433. /*______________________________________________________________________
  434.  
  435.     vol_DoEject - Process eject Button Hit.
  436.                     
  437.     Exit:        function result = error code.
  438.     
  439.     This routine must be called whenever there's a hit in the eject
  440.     button.  It ejects the currently selected volume, and unmounts it
  441.     if the unmount option was selected and the volume is not the
  442.     startup volume or the one containing the current application.  It 
  443.     then advances to the next on-line volume, hilites the Drive and 
  444.     eject buttons appropriately, and invalidates the volume name and 
  445.     icon rectangles.
  446.     
  447.     Don't forget to do a SetPort to the window before calling this routine.
  448. _____________________________________________________________________*/
  449.  
  450.  
  451. OSErr vol_DoEject (void)
  452.  
  453. {
  454.     HParamBlockRec    pBlock;                /* vol info param block */
  455.     OSErr                rCode;                /* result code */
  456.     short                volRefNum;            /* vol ref num of current vol */
  457.     
  458.     /* eject the current volume. */
  459.     
  460.     pBlock.volumeParam.ioNamePtr = nil;
  461.     pBlock.volumeParam.ioVolIndex = CurVol;
  462.     pBlock.volumeParam.ioVRefNum = 0;
  463.     if (rCode = PBHGetVInfo(&pBlock, false)) return rCode;
  464.     volRefNum = pBlock.volumeParam.ioVRefNum;
  465.     if (rCode = Eject(nil, volRefNum)) return rCode;
  466.     
  467.     /* If UnmountFlag is true, and the volume is not the system or
  468.         application volume, then unmount it. */
  469.         
  470.     if (UnmountFlag && volRefNum != SysVol && volRefNum != ApplVol) {
  471.         if (rCode = UnmountVol(nil, volRefNum)) return rCode;
  472.         CurVol = 0;
  473.     };
  474.     
  475.     /* Advance to next volume, hilite the buttons, and invalidate the 
  476.     rectangles. */
  477.         
  478.     if(rCode = NextVol()) return rCode;
  479.     HiliteDrive();
  480.     if (rCode = HiliteEject()) return rCode;
  481.     Inval();
  482.     return noErr;
  483. }
  484.  
  485. /*______________________________________________________________________
  486.  
  487.     vol_DoInsert - Process Disk Insertion Evect.
  488.     
  489.     Entry:    message = message field from event record.
  490.                     
  491.     Exit:        function result = error code.
  492.     
  493.     This routine must be called whenever there's a disk insertion event.
  494.     It makes the inserted volume the current volume, hilites the
  495.     Drive and eject buttons appropriately, and invalidates the volume
  496.     name and icon rectangles.
  497.     
  498.     Don't forget to do a SetPort to the window before calling this routine.
  499. _____________________________________________________________________*/
  500.  
  501.  
  502. OSErr vol_DoInsert (long message)
  503.  
  504. {
  505.     OSErr                rCode;                /* result code */
  506.     short                vRefNum;                /* vol ref num of inserted disk */
  507.  
  508.     /* Process the disk insertion event, and get the vol ref num */
  509.     
  510.     if (rCode = utl_DoDiskInsert(message, &vRefNum)) return rCode;
  511.     
  512.     /* Make the new disk the current volume. */
  513.     
  514.     if (rCode = vol_SetSel(vRefNum, true)) return rCode;
  515. }
  516.  
  517. /*______________________________________________________________________
  518.  
  519.     vol_DoUpdate - Process Update Event.
  520.                     
  521.     Exit:        function result = error code.
  522.     
  523.     This routine must be called whenever an update event occurs.  It
  524.     draws the volume name using the font attributes.  It also draws 
  525.     the proper small icon.
  526.     
  527.     If the current system supports popup menus, the volume name is also 
  528.     framed, with a drop shadow.
  529.     
  530.     Don't forget to do a SetPort to the window, call BeginUpdate, and
  531.     set your desired font and size before calling this routine.
  532. _____________________________________________________________________*/
  533.  
  534.  
  535. OSErr vol_DoUpdate (void)
  536.  
  537. {
  538.     HParamBlockRec    pBlock;                /* vol info param block */
  539.     Str255            volName;                /* vol name */
  540.     OSErr                rCode;                /* result code */
  541.     Rect                textRect;            /* rectangle for TextBox */
  542.     short                nameWidth;            /* width of vol name */
  543.     short                vRefNum;                /* vol ref num of cur vol */
  544.     short                slop;                    /* extra pixels needed in name width */
  545.     PolyHandle        triangle;            /* handle to triangle polygon */
  546.     
  547.     /* Return if there is no current volume. */
  548.     
  549.     if (!CurVol) return noErr;
  550.     
  551.     /* Get the volume name. */
  552.     
  553.     pBlock.volumeParam.ioNamePtr = volName;
  554.     pBlock.volumeParam.ioVolIndex = CurVol;
  555.     pBlock.volumeParam.ioVRefNum = 0;
  556.     if (rCode = PBHGetVInfo(&pBlock, false)) return rCode;
  557.     
  558.     /* If the name is too long truncate it and append the ellipsis char "…" */
  559.     
  560.     slop = HavePopUp ? 20 : 9;
  561.     while (true) {
  562.         nameWidth = StringWidth(volName);
  563.         if (NameRect->left + nameWidth + slop <= NameRect->right) break;
  564.         volName[0]--;
  565.         volName[volName[0]] = '…';
  566.     };
  567.  
  568.     /* Draw the volume name and icon. */
  569.     
  570.     textRect = *NameRect;
  571.     textRect.left += 4;
  572.     TextBox((Ptr)volName+1, *volName, &textRect, teJustLeft);
  573.     if (IconRect) {
  574.         if (rCode = vol_GetSel(&vRefNum)) return rCode;
  575.         utl_PlotSmallIcon (IconRect, utl_Ejectable(vRefNum) ? FloppyH : HardH);
  576.     };
  577.         
  578.     /* Frame the volume name, with a drop shadow, and draw the triangle. */
  579.         
  580.     if (HavePopUp) {
  581.         AdjNameRect = *NameRect;
  582.         AdjNameRect.right = AdjNameRect.left + nameWidth + slop;
  583.         InsetRect(&AdjNameRect, -1, -1);
  584.         FrameRect(&AdjNameRect);
  585.         MoveTo(AdjNameRect.right, AdjNameRect.top+2);
  586.         LineTo(AdjNameRect.right, AdjNameRect.bottom);
  587.         LineTo(AdjNameRect.left+2, AdjNameRect.bottom);
  588.         triangle = OpenPoly();
  589.         MoveTo(AdjNameRect.right - 14, 
  590.             (AdjNameRect.top + AdjNameRect.bottom - 5)>>1);
  591.         Line(10, 0);
  592.         Line(-5, 5);
  593.         Line(-5, -5);
  594.         ClosePoly();
  595.         PaintPoly(triangle);
  596.         KillPoly(triangle);
  597.     };
  598.     return noErr;
  599. }
  600.  
  601. /*______________________________________________________________________
  602.  
  603.     vol_Verify - Verify and Adjust Selected Volume.
  604.     
  605.     Exit:        function result = error code.
  606.     
  607.     This routine should be called after any call to the standard file
  608.     package or any other activity which might have caused the volume
  609.     list to change state. 
  610.     
  611.     vol_Verify checks to make sure that the current volume still exists and 
  612.     is online.  If it isn't, it finds some other volume that is and makes it 
  613.     the current one.  
  614.  
  615.     The volume name and icon rectangles are invalidated, and the Drive and 
  616.     eject buttons are rehilited appropriately.
  617.     _____________________________________________________________________*/
  618.  
  619.  
  620. OSErr vol_Verify (void)
  621.  
  622. {
  623.     HParamBlockRec    pBlock;            /* vol info param block */
  624.     OSErr                rCode;            /* reslut code */
  625.     
  626.     if (!CurVol) {
  627.         rCode = NextVol();
  628.     } else {
  629.         pBlock.volumeParam.ioNamePtr = nil;
  630.         pBlock.volumeParam.ioVolIndex = CurVol;
  631.         pBlock.volumeParam.ioVRefNum = 0;
  632.         rCode = PBHGetVInfo(&pBlock, false);
  633.         if ((rCode == nsvErr) || !pBlock.volumeParam.ioVDrvInfo) {
  634.             CurVol = 0;
  635.             rCode = NextVol();
  636.         };
  637.     };
  638.     if (rCode) return rCode;
  639.     HiliteDrive();
  640.     if (rCode = HiliteEject()) return rCode;
  641.     Inval();
  642. }
  643.  
  644. /*______________________________________________________________________
  645.  
  646.     vol_GetSel - Get Volume Reference Number of Selected Volume.
  647.     
  648.     Exit:        *vRefNum = volume reference number.
  649.                 function result = error code (= nsvErr if no current vol).
  650. _____________________________________________________________________*/
  651.  
  652.  
  653. OSErr vol_GetSel (short *vRefNum)
  654.  
  655. {
  656.     HParamBlockRec    pBlock;                /* vol info param block */
  657.     OSErr                rCode;                /* result code */
  658.     
  659.     if (!CurVol) return nsvErr;
  660.     pBlock.volumeParam.ioNamePtr = nil;
  661.     pBlock.volumeParam.ioVolIndex = CurVol;
  662.     pBlock.volumeParam.ioVRefNum = 0;
  663.     if (rCode = PBHGetVInfo(&pBlock, false)) return rCode;
  664.     *vRefNum = pBlock.volumeParam.ioVRefNum;
  665.     return noErr;
  666. }
  667.  
  668. /*______________________________________________________________________
  669.  
  670.     vol_SetSel - Set Volume Reference Number of Selected Volume.
  671.     
  672.     Entry:    vRefNum = volume reference number.
  673.                 doButtons = true to hilite Drive and eject buttons.
  674.     
  675.     Exit:        function result = error code.
  676. _____________________________________________________________________*/
  677.  
  678.  
  679. OSErr vol_SetSel (short vRefNum, Boolean doButtons)
  680.  
  681. {
  682.     HParamBlockRec    pBlock;                /* vol info param block */
  683.     OSErr                rCode;                /* result code */
  684.     
  685.     CurVol = 0;
  686.     pBlock.volumeParam.ioNamePtr = nil;
  687.     do {
  688.         pBlock.volumeParam.ioVolIndex = ++CurVol;
  689.         pBlock.volumeParam.ioVRefNum = 0;
  690.         rCode = PBHGetVInfo(&pBlock, false);
  691.     } while (!rCode && pBlock.volumeParam.ioVRefNum != vRefNum);
  692.     if (rCode) return rCode;
  693.     if (doButtons) {
  694.         HiliteDrive();
  695.         if (rCode = HiliteEject()) return rCode;
  696.     };
  697.     Inval();
  698.     return noErr;
  699. }
  700.  
  701. /*______________________________________________________________________
  702.  
  703.     vol_GetName - Get Name of Selected Volume.
  704.     
  705.     Exit:        vName = volume name.
  706.                 function result = error code (= nsvErr if no current vol).
  707. _____________________________________________________________________*/
  708.  
  709.  
  710. OSErr vol_GetName (Str255 *vName)
  711.  
  712. {
  713.     HParamBlockRec    pBlock;                /* vol info param block */
  714.     OSErr                rCode;                /* result code */
  715.     
  716.     if (!CurVol) return nsvErr;
  717.     
  718.     /* Get the volume name. */
  719.     
  720.     pBlock.volumeParam.ioNamePtr = (StringPtr)vName;
  721.     pBlock.volumeParam.ioVolIndex = CurVol;
  722.     pBlock.volumeParam.ioVRefNum = 0;
  723.     if (rCode = PBHGetVInfo(&pBlock, false)) return rCode;
  724.     return noErr;
  725. }